/**
 * objectloader.h
 * 
 * @author Zsolt Horváth 
 * @date   1. 4. 2011
 * 
 */

#ifndef OBJECTLOADER_H_
#define OBJECTLOADER_H_

#include <lib3ds.h>
#include <GL/glu.h>
#include <glm/glm.hpp>

#define MAX_CAMERA_COUNT 10
#define MAX_LIGHT_COUNT 8


/**
 * Vertex structure
 * 
 * This could be passed to VBO
 */
typedef struct TVertexColor {
    GLfloat ambient[4];
    GLfloat diffuse[4];
    GLfloat specular[4];
} VertexColor;

/**
 * Vertex structure
 * 
 * This could be passed to VBO
 */
typedef struct TObjectVertex {
    GLfloat position[3];
    GLfloat normal[3];
    VertexColor color;
} ObjectVertex;

/**
 * Index structure
 * 
 * This could be passed to EBO
 */
typedef struct TVertexIndices {
    GLuint index[3];
} VertexIndices;

/**
 * Camera structure
 */
typedef struct TCamera {
    glm::vec3 eye;
    glm::vec3 center;
    glm::vec3 up;
    GLfloat near;
    GLfloat far;
    GLfloat fovy;
    const char *name;
} Camera;

/**
 * Camera structure
 */
typedef struct TLight {
    GLfloat diffuse[3];
    GLfloat ambient[3];
    GLfloat specular[3];
    GLfloat position[4];
} Light;

/**
 * Struct of parsed object
 */
typedef struct TObject {
    ObjectVertex *vertices;
    VertexIndices *indices;
    unsigned int faceCount;
    unsigned int vertexCount;
    unsigned int indexCount;
    Camera *cameras[MAX_CAMERA_COUNT];
    unsigned int cameraCount;
    Light lights[MAX_LIGHT_COUNT];
    unsigned int lightCount;
} Object;

/**
 * 
 * 3DS object loader class
 * 
 */
class ObjectLoader {
    
    public:
        /**
         * Constructor
         * 
         * @param char *filename - path to 3DS file
         */
        ObjectLoader (char *filename);
        
        /**
         * Desctructor
         */
        ~ObjectLoader ();
        
        /**
         * Get vertices of loaded object
         * Returns array of vertices.
         * To get vertex count @see getVertexCount
         * 
         * @return pointer to ObjectVertex
         */
        ObjectVertex * getVertices();
        
        /**
         * Get indices of loaded object
         * Returns array of indices.
         * To get vertex count @see getIndexCount
         * 
         * @return pointer to VertexIndices
         */
        VertexIndices * getIndices();
        
        /**
         * Get face count  of object
         * 
         * @return number of faces
         */
        unsigned int getFaceCount ();
        
        /**
         * Get vertex count  of object
         * 
         * @return number of vertices
         */
        unsigned int getVertexCount ();
        
        /**
         * Get index count  of object
         * 
         * @return number of indices
         */        
        unsigned int getIndexCount ();

        /**
         * Get count  of cameras
         * 
         * @return number of cameras
         */        
        unsigned int getCameraCount ();
        
        /**
         * Get count  of lights
         * 
         * @return number of lights
         */        
        unsigned int getLightCount ();        
        
        /**
         * Get camera
         * 
         * @param int index - index of camera
         * @return pointer to camera, or NULL
         *         if index is out of range
         */
        Camera * getCamera (unsigned int index);
        
        /**
         * Get light
         * 
         * @param int index - index of light
         * @return Light
         */
        Light getLight (unsigned int index);        
        
    protected:
        /**
         * 3DS object file
         */
        Lib3dsFile *objectFile;
       
        /**
         * Struct of object
         */
        Object object;
        
        /**
         * Sizes of model, with, height, depth, and maximum of these
         */
        float sizeX, sizeY, sizeZ, sizeMax;
        
        /**
         * Bounding box positions
         */
        float boundingBoxMin[3], boundingBoxMax[3];
        
        /**
         * Object center point
         */
        glm::vec3 center;
        
        /**
         * Index pointer
         * 
         * Used while parsing nodes
         */
        unsigned int indexPointer;        
        
        /**
         * Init object
         * 
         * Alloc memory for indices and
         * vertices, and init counters
         * 
         * @return true if successfully initialized
         */
        bool initObject ();
        
        /**
         * Count faces recursively in nodes
         * 
         * @param Lib3dsNode *node - node of 3DS object file
         */
        void countFaces (Lib3dsNode *node) ;
        
        /**
         * Parse 3DS object
         */
        void parseObject ();
        
        /**
         * Parse node of object
         * 
         * Before calling this method, the initObject
         * method must be called.
         * @see initObject
         * 
         * @param Lib3dsNode *node - 3DS object file node
         */
        void parseNode (Lib3dsNode *node);
        
        /**
         * Create new camera
         * 
         * @return pointer to camera, or NULL of creation failed
         */
        Camera * createCamera ();
        
        /**
         * Add camera to object
         * 
         * @param Camera *camera - pointer to camera
         */
        void addCamera (Camera *camera);
        
        /**
         * Generate cameras
         */
        void generateCameras ();

        /**
         * Create light
         * 
         * @return initialized light
         */
        Light createLight ();
        
        /**
         * Add light to object
         * 
         * @param Light light - light structure
         */
        void addLight (Light light);
        
        /**
         * Generate lights
         */
        void generateLights ();
};

#endif /* OBJECTLOADER_H_ */